/**
 * Copyright (C) 2009 SC 4ViewSoft SRL
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ru.spbu.math.android.cbrf.charts.library;


import android.content.Context;
import android.content.Intent;
import ru.spbu.math.android.cbrf.charts.GraphicalView;
import ru.spbu.math.android.cbrf.charts.library.chart.LineChart;
import ru.spbu.math.android.cbrf.charts.library.chart.TimeChart;
import ru.spbu.math.android.cbrf.charts.library.chart.XYChart;
import ru.spbu.math.android.cbrf.charts.library.chart.renderer.DefaultRenderer;
import ru.spbu.math.android.cbrf.charts.library.chart.renderer.XYMultipleSeriesRenderer;
import ru.spbu.math.android.cbrf.charts.library.model.CategorySeries;
import ru.spbu.math.android.cbrf.charts.library.model.MultipleCategorySeries;
import ru.spbu.math.android.cbrf.charts.library.model.XYMultipleSeriesDataset;

/**
 * Utility methods for creating chart views or intents.
 */
public class ChartFactory {
    /**
     * The key for the chart data.
     */
    public static final String CHART = "chart";

    /**
     * The key for the chart graphical activity title.
     */
    public static final String TITLE = "title";

    private ChartFactory() {
        // empty for now
    }

    /**
     * Creates a line chart view.
     *
     * @param context  the context
     * @param dataset  the multiple series dataset (cannot be null)
     * @param renderer the multiple series renderer (cannot be null)
     * @return a line chart graphical view
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    public static final GraphicalView getLineChartView(Context context,
                                                       XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {
        checkParameters(dataset, renderer);
        XYChart chart = new LineChart(dataset, renderer);
        return new GraphicalView(context, chart);
    }

    /**
     * Creates a time chart view.
     *
     * @param context  the context
     * @param dataset  the multiple series dataset (cannot be null)
     * @param renderer the multiple series renderer (cannot be null)
     * @param format   the date format pattern to be used for displaying the X axis
     *                 date labels. If null, a default appropriate format will be used.
     * @return a time chart graphical view
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    public static final GraphicalView getTimeChartView(Context context,
                                                       XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String format) {
        checkParameters(dataset, renderer);
        TimeChart chart = new TimeChart(dataset, renderer);
        chart.setDateFormat(format);
        return new GraphicalView(context, chart);
    }


    /**
     * Creates a line chart intent that can be used to start the graphical view
     * activity.
     *
     * @param context  the context
     * @param dataset  the multiple series dataset (cannot be null)
     * @param renderer the multiple series renderer (cannot be null)
     * @return a line chart intent
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    public static final Intent getLineChartIntent(Context context, XYMultipleSeriesDataset dataset,
                                                  XYMultipleSeriesRenderer renderer) {
        return getLineChartIntent(context, dataset, renderer, "");
    }

    /**
     * Creates a time chart intent that can be used to start the graphical view
     * activity.
     *
     * @param context  the context
     * @param dataset  the multiple series dataset (cannot be null)
     * @param renderer the multiple series renderer (cannot be null)
     * @param format   the date format pattern to be used for displaying the X axis
     *                 date labels. If null, a default appropriate format will be used.
     * @return a time chart intent
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    public static final Intent getTimeChartIntent(Context context, XYMultipleSeriesDataset dataset,
                                                  XYMultipleSeriesRenderer renderer, String format) {
        return getTimeChartIntent(context, dataset, renderer, format, "");
    }


    /**
     * Creates a line chart intent that can be used to start the graphical view
     * activity.
     *
     * @param context       the context
     * @param dataset       the multiple series dataset (cannot be null)
     * @param renderer      the multiple series renderer (cannot be null)
     * @param activityTitle the graphical chart activity title. If this is null,
     *                      then the title bar will be hidden. If a blank title is passed in,
     *                      then the title bar will be the default. Pass in any other string
     *                      to set a custom title.
     * @return a line chart intent
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    public static final Intent getLineChartIntent(Context context, XYMultipleSeriesDataset dataset,
                                                  XYMultipleSeriesRenderer renderer, String activityTitle) {
        checkParameters(dataset, renderer);
        Intent intent = new Intent(context, GraphicalActivity.class);
        XYChart chart = new LineChart(dataset, renderer);
        intent.putExtra(CHART, chart);
        intent.putExtra(TITLE, activityTitle);
        return intent;
    }


    /**
     * Creates a time chart intent that can be used to start the graphical view
     * activity.
     *
     * @param context       the context
     * @param dataset       the multiple series dataset (cannot be null)
     * @param renderer      the multiple series renderer (cannot be null)
     * @param format        the date format pattern to be used for displaying the X axis
     *                      date labels. If null, a default appropriate format will be used
     * @param activityTitle the graphical chart activity title
     * @return a time chart intent
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    public static final Intent getTimeChartIntent(Context context, XYMultipleSeriesDataset dataset,
                                                  XYMultipleSeriesRenderer renderer, String format, String activityTitle) {
        checkParameters(dataset, renderer);
        Intent intent = new Intent(context, GraphicalActivity.class);
        TimeChart chart = new TimeChart(dataset, renderer);
        chart.setDateFormat(format);
        intent.putExtra(CHART, chart);
        intent.putExtra(TITLE, activityTitle);
        return intent;
    }

    /**
     * Checks the validity of the dataset and renderer parameters.
     *
     * @param dataset  the multiple series dataset (cannot be null)
     * @param renderer the multiple series renderer (cannot be null)
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset and the renderer don't include the same number of
     *                                  series
     */
    private static void checkParameters(XYMultipleSeriesDataset dataset,
                                        XYMultipleSeriesRenderer renderer) {
        if (dataset == null || renderer == null
                || dataset.getSeriesCount() != renderer.getSeriesRendererCount()) {
            throw new IllegalArgumentException(
                    "Dataset and renderer should be not null and should have the same number of series");
        }
    }

    /**
     * Checks the validity of the dataset and renderer parameters.
     *
     * @param dataset  the category series dataset (cannot be null)
     * @param renderer the series renderer (cannot be null)
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset number of items is different than the number of
     *                                  series renderers
     */
    private static void checkParameters(CategorySeries dataset, DefaultRenderer renderer) {
        if (dataset == null || renderer == null
                || dataset.getItemCount() != renderer.getSeriesRendererCount()) {
            throw new IllegalArgumentException(
                    "Dataset and renderer should be not null and the dataset number of items should be equal to the number of series renderers");
        }
    }

    /**
     * Checks the validity of the dataset and renderer parameters.
     *
     * @param dataset  the category series dataset (cannot be null)
     * @param renderer the series renderer (cannot be null)
     * @throws IllegalArgumentException if dataset is null or renderer is null or
     *                                  if the dataset number of items is different than the number of
     *                                  series renderers
     */
    private static void checkParameters(MultipleCategorySeries dataset, DefaultRenderer renderer) {
        if (dataset == null || renderer == null
                || !checkMultipleSeriesItems(dataset, renderer.getSeriesRendererCount())) {
            throw new IllegalArgumentException(
                    "Titles and values should be not null and the dataset number of items should be equal to the number of series renderers");
        }
    }

    private static boolean checkMultipleSeriesItems(MultipleCategorySeries dataset, int value) {
        int count = dataset.getCategoriesCount();
        boolean equal = true;
        for (int k = 0; k < count && equal; k++) {
            equal = dataset.getValues(k).length == dataset.getTitles(k).length;
        }
        return equal;
    }

}
